package com.sie.zhq.module;

import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;

import com.sie.zhq.constconfig.ConstDefine;
import com.sie.zhq.constconfig.ErrorDefine;
import com.sie.zhq.tool.ByteTool;

import java.io.FileInputStream;
import java.io.IOException;

/**金融模块固件升级
 * Created by zhq on 2016/8/4.
 */
public class FwUpdateModule {


    public DownloadThread downloadThread = null;
    public int iFileLen = 0;
    public boolean openFileFlag = false;
    public int openBinFileFlag = 0;
    public byte[] binBuffer = null;
    public int availableLen = 0;
    private int[] data = new int[100];
    SerialHelper mSerialControl = new SerialHelper(ConstDefine.FINANCIAL_PORT,115200);
    FinancialModule financialModule = FinancialModule.getInstance();
    DeviceCallback callback;
    boolean isOnMain ;
    public void setCallback( DeviceCallback callback,boolean isOnMain){

        this.callback =callback;
        this.isOnMain = isOnMain;
    }
    public void startDownload() {

        if (null != downloadThread && !downloadThread.isThreadFinished()) {
            Log.e("error", "Thread is still running");
            Bundle bundle = new Bundle();
            bundle.putInt("code", ErrorDefine.STILL_RUN);
            bundle.putString("message", "Thread is still running!");
            deliverResult(callback, DeviceInterface.Result.ERROR, bundle, isOnMain);
            return;
        }
        try {
            mSerialControl.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
        downloadThread = new DownloadThread();
        downloadThread.start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(1000);
                financialModule.PowerOff();
                SystemClock.sleep(1500);
                financialModule.PowerOn();

            }
        }).start();

    }


    public int readFile(String fileName) throws IOException {

        try {
            FileInputStream fin = new FileInputStream(fileName);
            availableLen = fin.available();
            //Log.i(tag, "availableLen = " + availableLen);

            binBuffer = new byte[availableLen];
            iFileLen = fin.read(binBuffer);
            if (iFileLen != availableLen) {
                fin.close();
                return -1;
            }

            Log.i("readFile", "iFileLen: " + iFileLen);
            fin.close();
            openBinFileFlag =1;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return 0;
    }


    private class DownloadThread extends Thread {
        private boolean m_bThreadFinished = false;
        int iRet = 0, totalPacket;
        byte i;
        byte data[] = new byte[2048];

        public boolean isThreadFinished() {
            return m_bThreadFinished;
        }

        DownloadThread() {
            this.setPriority(Thread.MIN_PRIORITY);

        }

        @Override
        public void run() {
            m_bThreadFinished = false;
//			Log.e("", "1111111111");
            if (openBinFileFlag == 0) {
                //SendMsg("Open a bin file first, please !", 0);
                Bundle bundle = new Bundle();
                bundle.putInt("code", ErrorDefine.FILE_ERR);
                bundle.putString("message", "FILE_ERR!");
                deliverResult(callback, DeviceInterface.Result.ERROR, bundle, isOnMain);
                m_bThreadFinished = true;
                return;
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            Log.e("HandShaking ...", "------");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            iRet = HandShake();


            if (iRet == 0) {
                DownloadFile();
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            mSerialControl.close();
            m_bThreadFinished = true;
        }
    }

    public int HandShake() {
        byte[] abyRecvBuff = new byte[1];
        byte[] abySendBuff = new byte[1];
        int iRet, i;

        Log.e("connecting...", "0...");

        i = 0;
        for (; i < 10; i++) {
            abySendBuff[0] = 'T';

            mSerialControl.send(abySendBuff);

            iRet = mSerialControl.Pop(abyRecvBuff, 1000);

            if (iRet == 0 && abyRecvBuff[0] == 'S') {
                abySendBuff[0] = 'Q';
                mSerialControl.send(abySendBuff);
                iRet = mSerialControl.Pop(abyRecvBuff, 3000);

                if (iRet == 0 && abyRecvBuff[0] == 'P') break;
            } else i--;
        }
        if (i != 10) {
            Log.e("Hand shack success !", "---next");
            return 0;
        }
        return 1;
    }

    public int DownloadFile() {
        int byteOffset = 0;
        int dwCurrentLen = 0;
        int iErrorCount = 0;
        int wPacketLen = 0;
        int iReadLen = 0;
        short iSendPacketLen = 0;
        int iRet;
        byte[] abyTemp = new byte[5000];
        byte[] abyCompress = new byte[50];

        short pwPacketetLen[] = new short[1];

        dwCurrentLen = 0;
        iErrorCount = 0;
        Log.d("DownloadFile", "iFileLen = " + iFileLen);
        deliverResult(callback, DeviceInterface.Result.START, null, isOnMain);
        while (true) {
            if (dwCurrentLen >= iFileLen) {
                break;
            }

            int progress = (dwCurrentLen * 100) / iFileLen;
            Log.e("Progress : ", progress + "%");

            Bundle bundle = new Bundle();
            bundle.putInt("data", progress);
            deliverResult(callback, DeviceInterface.Result.SUCCEED, bundle, isOnMain);

            wPacketLen = 512;
            if ((dwCurrentLen + 512) > iFileLen) {
                wPacketLen = (iFileLen - dwCurrentLen);
            }

            byteOffset += iReadLen;
            System.arraycopy(binBuffer, byteOffset, abyTemp, 5, wPacketLen);

            iReadLen = wPacketLen;

            if (iReadLen > 0) {
                abyTemp[0] = 0;
                abyTemp[1] = (byte) ((iReadLen / 65536) % 256);
                abyTemp[2] = (byte) ((iReadLen % 65536) / 256);
                abyTemp[3] = (byte) (iReadLen % 256);
                abyTemp[4] = 0;  // data no zip
                iSendPacketLen = (short) (iReadLen + 5);
                iErrorCount = 0;

                while (true) {
                    iRet = sendPackage(abyTemp, iSendPacketLen, (byte) 0xb0);
                    Log.e("", "Lib_SendPacket iRet = " + iRet);
                    if (iRet != 0) {
                        Log.e("", "Lib_SendPacket iRet = " + iRet);
                        return 10;
                    }
                    pwPacketetLen[0] = 0;
                    iRet = recvPacket(abyCompress, pwPacketetLen, 5000);
                    if ((0 == iRet) && (0x0B == abyCompress[5])) {

                        break;
                    }
                    iErrorCount++;
                    if (iErrorCount > 0) {
                        if (-1 == iRet) {
                            Log.e("Receive timeout!", "---");
                        } else {
                            Log.e("Receive failed!", "---");
                        }
                        return 5;
                    }
                }
                dwCurrentLen += iReadLen;
            } else {
                break;
            }
        }

        pwPacketetLen[0] = 0;

        sendPackage(abyTemp, (short) 0, (byte) 0xb1);
        iRet = recvPacket(abyCompress, pwPacketetLen, 5000);

        sendPackage(abyTemp, (short) 0, (byte) 0xD2);

        Log.e("DownLoad Success !", "!!!");
        deliverResult(callback, DeviceInterface.Result.COMPLETED, new Bundle(), isOnMain);
        return 0;
    }

    public int sendPackage(byte[] send, short length, byte cmd) {

        byte[] sendBuffer = new byte[length + 8];
        byte[] crcdata = new byte[length + 3];
        byte[] crc = new byte[4];

        sendBuffer[0] = 0x02;

        sendBuffer[1] = cmd;
        sendBuffer[2] = (byte) (length / 256);
        sendBuffer[3] = (byte) (length % 256);


        System.arraycopy(send, 0, sendBuffer, 4, length);
        System.arraycopy(sendBuffer, 1, crcdata, 0, length + 3);

        mSerialControl.Quick32Crc(crcdata, length + 3, crc);
        //QuickCrc32(crcdata, length + 3, crc);

        System.arraycopy(crc, 0, sendBuffer, length + 4, 4);

        //java.util.zip.CRC32();
        mSerialControl.send(sendBuffer);

        return 0;
    }

    public int recvPacket(byte[] pbyRecvData, short[] pwPacketetLen, int dwTimeoutMs) {
        int byRet;
        byte[] abyCrc32 = new byte[4];
        int i;
        byte[] ch = new byte[1];
        short wPacketLen = 0;
        int dwBegintick, dwCurtick;

        Log.d("", "begin");
        for (i = 0; i < dwTimeoutMs; i += 1000) {
            byRet = mSerialControl.Pop(ch, 1000);
            if ((0 == byRet) && (0x02 == ch[0])) {
                pbyRecvData[0] = ch[0];
                break;
            }
            try {
                Thread.sleep(50);//延时50ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (i >= dwTimeoutMs) {
            Log.d("", "timeout");
            return 104;

        }
        for (i = 1; i < 4; i++) {
            byRet = mSerialControl.Pop(ch, 1000); // timeout = 100ms
            if (0 != byRet) {
                return 101;
            }
            pbyRecvData[i] = ch[0];
        }
        wPacketLen = (short) (pbyRecvData[2] * 256 + pbyRecvData[3]);
        pwPacketetLen[0] = (short) (wPacketLen + 8);
        if (wPacketLen > 520) {
            return 103;
        }
        for (i = 4; i < wPacketLen + 8; i++) {
            byRet = mSerialControl.Pop(ch, 1000);
            if (0 != byRet) {
                return 101;
            }
            pbyRecvData[i] = ch[0];
        }
        Log.i("RecvPacket", "" + ByteTool.bytearrayToHexString(pbyRecvData, wPacketLen + 8));

        return 0;
    }
    protected static void deliverResult(final DeviceCallback callback, DeviceInterface.Result result, Bundle bundle, boolean onMainThread) {

        DeviceInterface.deliverResult(callback, result, bundle, onMainThread);

    }
}
